package es.usj.tac.meteorologica.controller;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.log4j.Logger;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import es.usj.tac.meteorologica.dao.DAOException;
import es.usj.tac.meteorologica.dao.DAOFactory;
import es.usj.tac.meteorologica.dto.City;
import es.usj.tac.meteorologica.dto.Country;
import es.usj.tac.meteorologica.dto.Weather;

/**
 * Clase que maneje el objeto respuesta de los WebServices.
 * <p>
 * Mediante esta clase servira para transformar los objetos que se reciben de 
 * las peticiones SOAP en formato XML a formato Bean para su manejo dentro de
 * la aplicacion del servidor y de esta manera poder realizar operaciones sobre 
 * los mismos.
 * <br/>
 * Se debe tener en cuenta que al emplear las clases de org.w3c tendra que 
 * tener un formato determinado, la cabecera debera estar con encoding UTF-8,
 * sino soltara errores en la lectura del documento. 
 * </p>
 * @author Alex, Sergio
 * @since 1.0
 * @version 1.2
 *
 */
public class XMLParser {

public XMLParser(){}

	private Weather weather=new Weather();
	
	private static final Logger log = Logger.getLogger(XMLParser.class);
	/**
	 * Parsea el XML a un Bean de Weather.
	 * A partir del XML que se pasa en formato String se obtienen los datos que 
	 * hay dentro y se crea un Bean Weather con esos datos.
	 * 
	 * @param xml el XML entero con formato de String.
	 * @return el XML parseado en formato Bean
	 */
	public Weather readXMLWeather(String xml) {
		log.debug("XML Entrada="+xml);
		 System.out.println("XML ENTRADA="+xml+"\n objeto="+(weather != null ? weather.toString() : "NULL"));
		
		try{
			InputStream inputXML = new ByteArrayInputStream(xml.getBytes());
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(inputXML);
			doc.getDocumentElement().normalize();
			Node rootNode = doc.getFirstChild();
			NodeList childs = rootNode.getChildNodes();
			for (int s = 0; s < childs.getLength(); s++) {
				Node fstNode = childs.item(s);
				if("Location".equals(fstNode.getNodeName())){
					String city[] = fstNode.getTextContent().split(", ");
					weather.setLocation(city[0]);
					City c=null;
					try {
						c = DAOFactory.getInstance().getCityDAO().readByName(city[0]);
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
					if(c != null)
						weather.setCity(c.getId());
					else
						weather.setCity(1);
				}else if("Time".equals(fstNode.getNodeName())){ 
					String date = "";
					try {
						String times[] = fstNode.getTextContent().split(" / ");
						String times1[] = times[1].split(" UTC");
						SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HHmm");
						SimpleDateFormat sdf2 = new SimpleDateFormat("dd/MM/yyyy HH:mm");
						Date dateParsed = sdf.parse(times1[0]);
						date = sdf2.format(dateParsed);
					} catch (Exception e) {
						log.error("Error formateando la fecha: "+fstNode.getTextContent(),e);
						date = new SimpleDateFormat("dd/MM/yyyy HH:mm").format(new Date());
					}
					weather.setTime(date);
				}else if("Wind".equals(fstNode.getNodeName())){
					weather.setWind(fstNode.getTextContent());
				}else if("Visibility".equals(fstNode.getNodeName())){
					weather.setVisibility(fstNode.getTextContent());
				}else if("Temperature".equals(fstNode.getNodeName())){
					String temp = fstNode.getTextContent().trim();
					String[] temps = temp.split("F");
					int inF = new Integer(temps[0].trim()).intValue();
					String parsed = temps[1].replace("(", "");
					parsed = parsed.replace(")", "");
					parsed = parsed.replace("C", "");
					int inC = new Integer(parsed.trim()).intValue();
					weather.setTemperatureInF(inF);
					weather.setTemperatureInC(inC);
				}else if("DewPoint".equals(fstNode.getNodeName())){
					String temp = fstNode.getTextContent().trim();
					String[] temps = temp.split("F");
					int inF = new Integer(temps[0].trim()).intValue();
					String parsed = temps[1].replace("(", "");
					parsed = parsed.replace(")", "");
					parsed = parsed.replace("C", "");
					int inC = new Integer(parsed.trim()).intValue();
					weather.setDewPointInF(inF);
					weather.setDewPointInC(inC);
				}else if("RelativeHumidity".equals(fstNode.getNodeName())){
					weather.setRelativeHumidity(new Double(fstNode.getTextContent().replace("%", "")).doubleValue());
				}else if("Pressure".equals(fstNode.getNodeName())){
					weather.setPressure(fstNode.getTextContent());
				}else if("Status".equals(fstNode.getNodeName())){
					if("Success".equals(fstNode.getTextContent()))
						weather.setStatus(true);
					else
						weather.setStatus(false);
				}
			}
			log.debug("DTO Parseado="+weather.toString());
			return weather;
		}catch(ParserConfigurationException e){
			log.error("Error parseando el XML con la configuracion, el XML es="+xml,e);
			return null;
		} catch (SAXException e) {
			log.error("Error parseando el XML con la SAX, el XML es="+xml,e);
			return null;
		} catch (IOException e) {
			log.error("Error parseando el XML con la IOException, el XML es="+xml,e);
			return null;
		} 
	}
	/**
	 * Parsea el XML de las ciudades.
	 * A partir del XML que se pasa en formato String se obtienen los datos que 
	 * hay dentro y se crea un {@link java.util.List List<City>} con esos datos.
	 * @param xml la respuesta
	 * @return el listado con las ciudades leidas.
	 */
	public List<City> readXMLCities(String xml){
		List<City> citiesArray = new ArrayList<City>();
		try {
			
			InputStream inputXML = new ByteArrayInputStream(xml.getBytes());
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(inputXML);
			doc.getDocumentElement().normalize();
			Node rootNode = doc.getFirstChild();
			NodeList childs = rootNode.getChildNodes();
			for (int s = 0; s < childs.getLength(); s++) {
				Node fstNode = childs.item(s);
				NodeList cities = fstNode.getChildNodes();
				City city = new City();
				for(int i=0;i< cities.getLength();i++){
					Node node =cities.item(i);
					if("Country".equals(node.getNodeName())){
						Country c = DAOFactory.getInstance().getCountryDAO().readByName(node.getTextContent());
						if(c!= null)
							city.setPoblation(c.getId());
						else{
							city.setPoblation(9999);
						}
					}else if("City".equals(node.getNodeName()))
						city.setName(node.getTextContent());
				}
				if(city.getName() != null & city.getPoblation() > 0)
					citiesArray.add(city);
			} 
			
			return citiesArray;
		} catch (ParserConfigurationException e) {
			log.error("Error creando el DocumentBuilder",e);
			return null;
		} catch (SAXException e) {
			log.error("Error parseando el XML="+xml,e);
			return null;
		} catch (IOException e) {
			log.error("Error con el XML="+xml,e);
			return null;
		} catch (DOMException e) {
			log.error("Error obteniendo el contenido del nodo: ",e);
			return null;
		} catch (DAOException e) {
			log.error("Error leyendo de la base de datos ",e);
			return null;
		}
	}

	/**
	 * @return the weather
	 */
	public Weather getWeather() {
		return weather;
	}
	/**
	 * @param weather the weather to set
	 */
	public void setWeather(Weather weather) {
		this.weather = weather;
	}
}
